#!/usr/bin/env bun

import path from "path"
import protobuf from "protobufjs"
import { decodeTest2 } from "./decodeTest.js"
import assert from "assert"

const encode = (t, payload) => t.encode(t.create(payload)).finish()

const root = await protobuf.load(
		path.resolve(import.meta.dirname, "demo.proto"),
	),
	Test2 = root.lookupType("demo.Test2")

const payload = {
	f1: 1.23,
	f2: 4.56,
	f3: -7,
	f4: -8,
	f5: 9,
	f6: 10,
	f7: -11,
	f8: -12,
	f9: 13,
	f10: 14,
	f11: -15,
	f12: -16,
	f13: true,
	f14: "hello world",
	f15: new Uint8Array([1, 2, 3]),
	f16: [1.1, 2.2],
	f17: [3.3, 4.4],
	f18: [-5, -6],
	f19: [-7, -8],
	f20: [9, 10],
	f21: [11, 12],
	f22: [-13, -14],
	f23: [-15, -16],
	f24: [17, 18],
	f25: [19, 20],
	f26: [-21, -22],
	f27: [-23, -24],
	f28: [true, false],
	f29: ["abc", "efghijklmn"],
	f30: [new Uint8Array([4, 5]), new Uint8Array([6, 7])],
	test1: { id: 133222, name: "John Doe" },
	test1li: [
		{ id: 10322, name: "one" },
		{ id: 23222, name: "two" },
	],
}

const data = encode(Test2, payload)
console.log("encoded length with test1li", data.length)
const decoded = decodeTest2(data)
console.log(decoded)

assert.strictEqual(decoded[0], payload.f1)
assert.ok(Math.abs(decoded[1] - payload.f2) < 0.0001) // float precision
assert.strictEqual(decoded[2], payload.f3)
assert.strictEqual(decoded[3], payload.f4)
assert.strictEqual(decoded[4], payload.f5)
assert.strictEqual(decoded[5], payload.f6)
assert.strictEqual(decoded[6], payload.f7)
assert.strictEqual(decoded[7], payload.f8)
assert.strictEqual(decoded[8], payload.f9)
assert.strictEqual(decoded[9], BigInt(payload.f10)) // fixed64 is BigInt
assert.strictEqual(decoded[10], payload.f11)
assert.strictEqual(decoded[11], BigInt(payload.f12)) // sfixed64 is BigInt
assert.strictEqual(decoded[12], payload.f13)
assert.strictEqual(decoded[13], payload.f14)
assert.deepStrictEqual(decoded[14], Buffer.from(payload.f15))

// Assertions for repeated fields
assert.deepStrictEqual(decoded[15], payload.f16) // double
decoded[16].forEach((v, i) => assert.ok(Math.abs(v - payload.f17[i]) < 0.0001)) // float
assert.deepStrictEqual(decoded[17], payload.f18) // int32
assert.deepStrictEqual(decoded[18], payload.f19) // int64 (as numbers)
assert.deepStrictEqual(decoded[19], payload.f20) // uint32
assert.deepStrictEqual(decoded[20], payload.f21) // uint64 (as numbers)
assert.deepStrictEqual(decoded[21], payload.f22) // sint32
assert.deepStrictEqual(decoded[22], payload.f23) // sint64 (as numbers)
assert.deepStrictEqual(decoded[23], payload.f24) // fixed32
assert.deepStrictEqual(decoded[24], payload.f25.map(BigInt)) // fixed64
assert.deepStrictEqual(decoded[25], payload.f26) // sfixed32
assert.deepStrictEqual(decoded[26], payload.f27.map(BigInt)) // sfixed64
assert.deepStrictEqual(decoded[27], payload.f28) // bool
assert.deepStrictEqual(decoded[28], payload.f29) // string
assert.deepStrictEqual(
	decoded[29].map((b) => Buffer.from(b)),
	payload.f30.map((b) => Buffer.from(b)),
) // bytes

assert.deepStrictEqual(decoded[30], [payload.test1.id, payload.test1.name])
assert.deepStrictEqual(
	decoded[31],
	payload.test1li.map((t) => [t.id, t.name]),
)

console.log("All tests passed!")
